package cn.amossun.starter.event.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.amossun.starter.event.annoation.EventListener;
import cn.amossun.starter.event.annoation.EventMulticaster;
import cn.amossun.starter.event.annoation.EventPublisher;
import cn.amossun.starter.event.annoation.EventBinding;
import cn.amossun.starter.event.common.Constants;
import cn.amossun.starter.event.enums.ExchangeTypeEnum;
import cn.amossun.starter.event.property.EventBindingContext;
import cn.amossun.starter.event.property.EventContext;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Data
@Slf4j
@AllArgsConstructor
public class EventBindingContextProcessor implements BindingContextHolder {

    private EventContext eventContext;

    private EventQueueContextProcessor eventQueueContextProcessor;

    private EventExchangeContextProcessor eventExchangeContextProcessor;

    @Override
    public void processListener(Object bean, String beanName, Method method) {
        EventListener eventListener = AnnotationUtils.findAnnotation(method, EventListener.class);
        if (eventListener != null) {
            eventContext.addBindings(beanName, method.getName(), buildEventBindingsContexts(eventListener, getRoutingKey(eventListener), eventQueueContextProcessor.getQueueName(bean, beanName, method)));
        }
    }

    @Override
    public void processPublisher(Object bean, String beanName, Method method) {
        EventPublisher eventPublisher = AnnotationUtils.findAnnotation(method, EventPublisher.class);
        if (eventPublisher != null) {
            eventContext.addBinding(beanName, method.getName(), buildEventBindingsContext(eventPublisher));
        }
    }

    @Override
    public void processMulticaster(Object bean, String beanName, Method method) {
        EventMulticaster eventMulticaster = AnnotationUtils.findAnnotation(method, EventMulticaster.class);
        if (eventMulticaster != null) {

        }
    }

    @Override
    public List<EventBindingContext> buildEventBindingsContexts(EventListener eventListener, String defaultListenerKey, String defaultQueueName) {
        if(eventListener.bindings().length > 0
                && CollectionUtil.isNotEmpty(Arrays.stream(eventListener.bindings()).map(EventBinding::queue).collect(Collectors.toList()))){

            return Arrays.stream(eventListener.bindings()).map(eventBinding -> {
                return process(eventBinding, eventListener.definition());
            }).collect(Collectors.toList());
        }

        EventBindingContext eventBindingContext = new EventBindingContext(
                defaultListenerKey,
                Constants.EVENT_TOPIC_EXCHANGE,
                ExchangeTypeEnum.TOPIC,
                defaultQueueName,
                getArguments(eventListener.arguments()));
        return Arrays.asList(eventBindingContext);
    }

    @Override
    public EventBindingContext buildEventBindingsContext(EventPublisher eventPublisher) {

        if(eventPublisher.binding() != null && StrUtil.isNotEmpty(eventPublisher.binding().key()) &&
                eventPublisher.binding().exchange() != null && StrUtil.isNotEmpty(eventPublisher.binding().exchange().name()) && StrUtil.isNotEmpty(eventPublisher.binding().exchange().value())) {
            return process(eventPublisher.binding(), eventPublisher.definition());
        }

        if(eventPublisher.exchange() != null &&
                StrUtil.isNotEmpty(eventPublisher.exchange().name()) && StrUtil.isNotEmpty(eventPublisher.exchange().value())) {
            EventBindingContext eventBindingContext = new EventBindingContext(
                    String.format(Constants.ROUTING_KEY_TEMPLATE, eventPublisher.key(), eventPublisher.definition().getCode()),
                    eventPublisher.exchange().name(),
                    eventPublisher.exchange().type(),
                    null,
                    getArguments(eventPublisher.exchange().arguments()));
            return eventBindingContext;
        }

        /*String defaultExchangeName = getDefaultExchangeName(eventPublisher.defaultTopicExchange(), eventPublisher.defaultHeadersExchange());

        ExchangeTypeEnum exchangeTypeEnum = getDefaultExchangeTypeEnum(eventPublisher.defaultTopicExchange(), eventPublisher.defaultHeadersExchange());

        EventBindingContext eventBindingContext = new EventBindingContext(
                String.format(Constants.ROUTING_KEY_TEMPLATE, eventPublisher.key(), eventPublisher.definition().getCode()),
                defaultExchangeName,
                exchangeTypeEnum,
                null,
                getArguments(eventPublisher.arguments()));

        return eventBindingContext;*/

        return null;
    }

}
